package org.cnc.app;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.KeyEventPostProcessor;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowEvent;
import java.rmi.RemoteException;
import java.rmi.server.ServerNotActiveException;

import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.SwingUtilities;

import org.cnc.rmi.interfaces.RmiServer;

public abstract class ServerModule<Server extends RmiServer> implements KeyEventPostProcessor {

	protected short DEFAULT_PORT = 3100;
	protected String DEFAULT_NAME = "module";
	
	protected JFrame frame;
	protected boolean isFullScreenOn = false;
	protected short serverPort;
	protected String serverName;
	protected ServerSettings settings;
	protected Server server;
	
	public ServerModule( Server server ) throws RemoteException, ServerNotActiveException 
	{     
		this.server = server;
		this.DEFAULT_NAME = server.getName();
		this.DEFAULT_PORT = (short) server.getPort();
		
		this.serverPort = DEFAULT_PORT;
		this.serverName = DEFAULT_NAME;
		
		frame = new JFrame(serverName);
	    
	    startServer();
	    
	    frame.setSize(1046, 755);
	    frame.setLocation(300,200);
	    frame.getContentPane().setLayout(new BorderLayout(0, 0));
	    
	    settings = new ServerSettings();

		frame.add(settings, BorderLayout.NORTH);
	    
	    frame.setVisible(true);
	    frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
	}

	
	@Override
	public boolean postProcessKeyEvent(final KeyEvent arg0) {
		
        if (arg0.getID() == KeyEvent.KEY_PRESSED) { 
        	
			if ( arg0.isControlDown() && arg0.getKeyCode() == KeyEvent.VK_S )
				showSettings();
			else if ( arg0.isControlDown() && arg0.getKeyCode() == KeyEvent.VK_F )
				toggleFullScreen();
			else if ( arg0.getKeyCode() == KeyEvent.VK_ESCAPE )
			{
	            WindowEvent wev = new WindowEvent(frame, WindowEvent.WINDOW_CLOSING);
	            Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(wev);
			}
        } 
		return false;
	}

	private void toggleFullScreen() {
		
	    frame.dispose();
		
		SwingUtilities.invokeLater(new Runnable() {
		  public void run() {
		
			if ( !isFullScreenOn )
			{
				GraphicsEnvironment localEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
				GraphicsDevice defaultDevice = localEnvironment.getDefaultScreenDevice();
				
				frame.setState(JFrame.MAXIMIZED_BOTH);
				frame.setUndecorated(true);
				
				defaultDevice.setFullScreenWindow(frame);
			
				isFullScreenOn = true;
				
				frame.setVisible(true);
				
				return;
			}
			else
			{
			
				GraphicsEnvironment localEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
				GraphicsDevice defaultDevice = localEnvironment.getDefaultScreenDevice();
				
				frame.setState(JFrame.NORMAL);
				frame.setUndecorated(false);
				
				defaultDevice.setFullScreenWindow(null);
				
				isFullScreenOn = false;
				
				frame.setVisible(true);
				
				return;
			}
			
		}});
	
	}

	private void showSettings()
	{
		if ( !settings.isVisible() )
		{
			settings.updatePanel();
			settings.setVisible(true);	
		}
		else
			settings.setVisible(false);
	}
	
	private void saveSettings( String port, String name )
	{
		try
		{
			short portVal = Integer.valueOf(port).shortValue();
			
			if ( portVal != DEFAULT_PORT )
				serverPort = portVal;
			
			if ( !name.equals(DEFAULT_NAME) )
				serverName = name;
		}
		catch ( Exception e)
		{
			serverPort = DEFAULT_PORT;
			serverName = DEFAULT_NAME;
		}
		
		settings.setVisible(false);
		startServer();
	}
	
	private void startServer()
	{
		try
		{
			if ( server != null && serverPort == DEFAULT_PORT )
				return;
			else if ( server != null )
				server.unbind();
			
			server.rebind(serverName, serverPort);
		}
		catch (RemoteException e)
		{
			e.printStackTrace();
		}
	}
	
	@SuppressWarnings("serial")
	class ServerSettings extends JPanel
	{
		private JTextField txtServerPort;
		private JTextField txtServerName;
		private JLabel label;
		
		public void updatePanel()
		{
			label.setText( server.getStatus() );
			txtServerPort.setText( Integer.toString(serverPort) );
			txtServerName.setText( serverName );
		}
		
		public ServerSettings()
		{
			setPreferredSize(new Dimension(120,120));
			
			JLabel lblServerPort = new JLabel("Server port:");
			lblServerPort.setFont(new Font("Tahoma", Font.PLAIN, 16));
			
			txtServerPort = new JTextField( Integer.toString(serverPort) );
			txtServerPort.setFont(new Font("Tahoma", Font.PLAIN, 16));
			txtServerPort.setColumns(10);
			
			JLabel lblCurrentStatus = new JLabel("Current status");
			lblCurrentStatus.setFont(new Font("Tahoma", Font.PLAIN, 16));
			
			label = new JLabel( server.getStatus() );
			label.setFont(new Font("Tahoma", Font.PLAIN, 16));
			
			JButton btnOk = new JButton("Save");
			btnOk.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0)
				{
					saveSettings(txtServerPort.getText(), txtServerName.getText());
				}
			});
			
			JLabel lblServerName = new JLabel("Server name:");
			lblServerName.setFont(new Font("Tahoma", Font.PLAIN, 16));
			
			txtServerName = new JTextField( serverName );
			txtServerName.setFont(new Font("Tahoma", Font.PLAIN, 16));
			txtServerName.setColumns(10);
			
			GroupLayout groupLayout = new GroupLayout(this);
			groupLayout.setHorizontalGroup(
				groupLayout.createParallelGroup(Alignment.LEADING)
					.addGroup(groupLayout.createSequentialGroup()
						.addContainerGap()
						.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
							.addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
								.addGroup(groupLayout.createSequentialGroup()
									.addComponent(lblServerPort)
									.addGap(28))
								.addGroup(groupLayout.createSequentialGroup()
									.addComponent(lblServerName)
									.addGap(18)))
							.addComponent(lblCurrentStatus))
						.addGap(28)
						.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
							.addComponent(label, GroupLayout.DEFAULT_SIZE, 155, Short.MAX_VALUE)
							.addComponent(txtServerPort, GroupLayout.DEFAULT_SIZE, 155, Short.MAX_VALUE)
							.addComponent(txtServerName, GroupLayout.DEFAULT_SIZE, 146, Short.MAX_VALUE))
						.addGap(100)
						.addComponent(btnOk, GroupLayout.PREFERRED_SIZE, 62, GroupLayout.PREFERRED_SIZE)
						.addContainerGap())
			);
			groupLayout.setVerticalGroup(
				groupLayout.createParallelGroup(Alignment.LEADING)
					.addGroup(groupLayout.createSequentialGroup()
						.addContainerGap()
						.addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
							.addComponent(btnOk)
							.addComponent(lblServerPort)
							.addComponent(txtServerPort, GroupLayout.PREFERRED_SIZE, 23, GroupLayout.PREFERRED_SIZE))
						.addPreferredGap(ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
						.addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
							.addComponent(lblServerName)
							.addComponent(txtServerName, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
						.addPreferredGap(ComponentPlacement.UNRELATED)
						.addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
							.addComponent(label, GroupLayout.PREFERRED_SIZE, 26, GroupLayout.PREFERRED_SIZE)
							.addComponent(lblCurrentStatus))
						.addContainerGap())
			);
			setLayout(groupLayout);

		}
	}
}
